#include "Connection.h"
#include "ConnectionHandler.h"
#include "Service.h"
extern "C" {
#include <event2/event.h>
#include <event.h>
#include <event2/listener.h>
};

Connection::Connection( bufferevent* bev, Service* service )
{
	m_bev = bev;
	m_service = service;
	m_handler = NULL;
	m_tmrClose = NULL;
	bufferevent_setcb(m_bev, onBevRead, NULL, onBevEvent, this);
	bufferevent_enable(m_bev, EV_READ);
}

Connection::Connection( Service* service )
{
	m_service = service;
	m_handler = NULL;
	m_tmrClose = NULL;
	m_bev = NULL;
}

void Connection::setHandler( ConnectionHandler* handler )
{
	m_handler = handler;
}

void Connection::onBevRead( bufferevent* bev, void* args )
{
	Connection* connection = (Connection*)args;
	
	if(connection->m_handler) {
		connection->m_handler->onData(connection);
	}
}

void Connection::onBevEvent( bufferevent* bev, short ev, void* args )
{
	Connection* connection = (Connection*)args;
	
	
	if(connection->m_handler) {
	
		if(ev == BEV_EVENT_CONNECTED) {
			bufferevent_enable(bev, EV_READ);
			connection->m_handler->onConnected(connection);
		} else {
			connection->m_handler->onClose(connection);
			delete connection;
		}
		
	}
}

bufferevent* Connection::getBev()
{
	return m_bev;
}

void Connection::close()
{
	if(m_tmrClose) {
		return;
	}
	m_tmrClose = evtimer_new(m_service->getBase(), &Connection::onTmrClose, this);
	timeval val = {0, 0};
	evtimer_add(m_tmrClose, &val);
}

int Connection::getId()
{
	static unsigned int id = 0;
	return id++;
}

void Connection::sendData( char* data, int len )
{
	bufferevent_write(m_bev, data, len);
}

void* Connection::getUserData()
{
	return m_userData;
}

void Connection::setUserData( void* ptr)
{
	m_userData  = ptr;
}

Connection::~Connection()
{
	this->realClose();
}

void Connection::onTmrClose( intptr_t fd, short ev, void* args )
{
	Connection* conn = (Connection*)args;
	conn->realClose();
	delete conn;
}

void Connection::realClose()
{
	if(m_tmrClose) {
		evtimer_del(m_tmrClose);
		event_free(m_tmrClose);
		m_tmrClose = NULL;
	}

	if(m_bev) {
		bufferevent_disable(m_bev, EV_READ);
		evutil_closesocket(bufferevent_getfd(m_bev));
		bufferevent_free(m_bev);
		m_bev = NULL;		
	}
}

void Connection::connect( std::string ip, int port )
{
	m_ip = ip;
	m_port = port;

	m_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	sockaddr_in addr = {};
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(ip.c_str());
	evutil_make_socket_nonblocking(m_fd);
	m_bev = bufferevent_socket_new(m_service->getBase(), m_fd, BEV_OPT_DEFER_CALLBACKS);
	bufferevent_setcb(m_bev, onBevRead, NULL, onBevEvent, this);
	bufferevent_socket_connect(m_bev, (sockaddr*)&addr, sizeof(sockaddr_in));
}
